import os
import subprocess
import shutil
import uuid
from chernc.compiler.sfc.compilation import CompilationContextSFC
from chernc.utils.hash_utils import calculate_md5
from chernc.utils.file_utils import write_file, read_file

class RustCompilationContextSFC(CompilationContextSFC):
    def __init__(self, temp_dir: str = "./temp_dir"):
        self.temp_dir = temp_dir
        os.makedirs(self.temp_dir, exist_ok=True)
        self.project_id = str(uuid.uuid4())
        self.project_name = f"project_{self.project_id}"
        self.project_dir = os.path.join(self.temp_dir, self.project_name)
        os.makedirs(self.project_dir, exist_ok=True)
        self.code_path = f"{self.project_id}.rs"
        self.out_bin_path = f"{self.project_id}"
    
    def write_code(self, code: str) -> bool:
        """
        Write the code to the code path
        code: the code to write
        return: True if the code was written successfully, False otherwise
        """
        try:
            write_file(os.path.join(self.project_dir, self.code_path), code)
            return True
        except Exception as e:
            print(f"Error writing code to {self.code_path}: {e}")
            return False
    
    def read_code(self) -> str:
        """
        Read the code from the code path
        return: the code as a string
        """
        return read_file(os.path.join(self.project_dir, self.code_path))
    
    def compile(self) -> str:
        """
        Compile the code
        return: the compile output as a string
        """
        try:
            compile_output = subprocess.check_output(f"rustc {self.code_path} -o {self.out_bin_path}", cwd=self.project_dir, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=60)
        except subprocess.CalledProcessError as e:
            compile_output = e.output
            if isinstance(compile_output, bytes):
                compile_output = compile_output.decode("utf-8")
            return compile_output
        except subprocess.TimeoutExpired as e:
            compile_output = e.output
            if isinstance(compile_output, bytes):
                compile_output = compile_output.decode("utf-8")
            return compile_output
        if isinstance(compile_output, bytes):
            compile_output = compile_output.decode("utf-8")
        return compile_output

    def run(self) -> str:
        """
        Run the compiled binary
        return: the run output as a string
        """
        if not os.path.exists(os.path.join(self.project_dir, self.out_bin_path)):
            raise FileNotFoundError(f"The compiled binary {self.out_bin_path} does not exist, please compile the project first")
        try:
            output = subprocess.check_output(f"./{self.out_bin_path}", cwd=self.project_dir, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=60)
        except subprocess.CalledProcessError as e:
            return e.output
        except subprocess.TimeoutExpired as e:
            return e.output
        if isinstance(output, bytes):
            output = output.decode("utf-8")
        return output
    
    def clean(self):
        """
        Clean up the temporary files
        """
        shutil.rmtree(self.project_dir)
